﻿#region License
// MIT License
//
// Copyright(c) 2019-2025 ZhangYu
// https://gitee.com/zhangyu800/litebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#region Intro
// Purpose: Parse bytes to base type
// Author: ZhangYu
// CreateDate: 2019-08-13
// LastModifiedDate: 2025-08-26
#endregion
namespace LiteByte.Converters {

    using System;
    using System.Runtime.CompilerServices;

    /// <summary> 数字类型读取器(比特、整数、浮点数、变长整数) | Number type reader(bit、int、float、vint) </summary>
    public class NumberReader : IDisposable {

        #region 字段 | Fields
        private static readonly int[] BitMask = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF];
        private static readonly uint[] VInt32SignMask = [0, 0x80, 0x8000, 0x800000, 0x80000000];
        private static readonly uint[] VInt32ValueMask = [0, 0x7F, 0x7FFF, 0x7FFFFF, 0x7FFFFFFF];
        private static readonly ulong[] VInt64SignMask = [0, 0x80, 0x8000, 0x800000, 0x80000000, 0x8000000000, 0x800000000000, 0x80000000000000, 0x8000000000000000];
        private static readonly ulong[] VInt64ValueMask = [0, 0x7F, 0x7FFF, 0x7FFFFF, 0x7FFFFFFF, 0x7FFFFFFFFF, 0x7FFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF];
        protected byte[] bytes;
        protected int byteIndex;
        protected int bitByteIndex = -1;
        protected int bitIndex = 8;
        #endregion

        #region 构造方法 | Constructors
        public NumberReader() { }

        public NumberReader(byte[] bytes) {
            this.bytes = bytes;
        }
        #endregion

        #region 比特 | Bit
        /// <summary> 读取1位整数 转为布尔型(0=false、1=true) | Read 1-bit integer(0=false、1=true) </summary>
        public bool ReadBit1() {
            return ReadBits(1) != 0;
        }

        /// <summary> 读取2位整数 | Read 2-bit integer </summary>
        public byte ReadBit2() {
            return ReadBits(2);
        }

        /// <summary> 读取3位整数 | Read 3-bit integer </summary>
        public byte ReadBit3() {
            return ReadBits(3);
        }

        /// <summary> 读取4位整数 | Read 4-bit integer </summary>
        public byte ReadBit4() {
            return ReadBits(4);
        }

        /// <summary> 读取5位整数 | Read 5-bit integer </summary>
        public byte ReadBit5() {
            return ReadBits(5);
        }

        /// <summary> 读取6位整数 | Read 6-bit integer </summary>
        public byte ReadBit6() {
            return ReadBits(6);
        }

        /// <summary> 读取7位整数 | Read 7-bit integer </summary>
        public byte ReadBit7() {
            return ReadBits(7);
        }

        /// <summary> 读取8位整数 | Read 8-bit integer </summary>
        public byte ReadBit8() {
            return ReadBits(8);
        }

        /// <summary> 读取1~8位整数 | Read 1~8 bit integer </summary>
        /// <param name="bitCount">位数(1~8)</param>
        public byte ReadBits(int bitCount) {
            if (bitCount < 1 || bitCount > 8) throw new ArgumentOutOfRangeException("bitCount", $"bitCount: {bitCount} out of range! bitCount valid range:1 ~ 8");
            int usableBits = 8 - bitIndex;
            if (usableBits >= bitCount) {
                // 读取当前字节
                int value = (bytes[bitByteIndex] >> bitIndex) & BitMask[bitCount];
                bitIndex += bitCount;
                return (byte)value;
            } else if (usableBits > 0) {
                // 跨字节读取
                int lowBits = (bytes[bitByteIndex] >> bitIndex) & BitMask[usableBits];
                bitByteIndex = byteIndex++;
                int highBits = (bytes[bitByteIndex] & BitMask[bitCount - usableBits]) << usableBits;
                int value = lowBits | highBits;
                bitIndex = bitCount - usableBits;
                return (byte)value;
            } else {
                // 读取下一个字节
                bitByteIndex = byteIndex++;
                int value = bytes[bitByteIndex] & BitMask[bitCount];
                bitIndex = bitCount;
                return (byte)value;
            }
        }
        #endregion

        #region 整数 | Integer
        /// <summary> 读取布尔型(1字节 0=true 1=false) | Read Boolean(1 byte 0=true 1=false) </summary>
        public bool ReadBool() {
            return ReadUInt8() != 0;
        }

        /// <summary> 读取字符型(2字节 无符号整数) | Read Char(2 bytes unsigned integer) </summary>
        public char ReadChar() {
            return (char)ReadUInt16();
        }

        /// <summary> 读取UInt8(1字节 无符号整数) | Read UInt8(1 byte unsigned integer) </summary>
        public byte ReadUInt8() {
            return bytes[byteIndex++];
        }

        /// <summary> 读取Int8(1字节 有符号整数) | Read UInt8(1 byte signed integer) </summary>
        public sbyte ReadInt8() {
            return (sbyte)bytes[byteIndex++];
        }

        /// <summary> 读取UInt16(2字节 无符号整数 小端序) | Read UInt16(2 bytes unsigned integer little-endian) </summary>
        public ushort ReadUInt16() {
            ushort value = Unsafe.As<byte, ushort>(ref bytes[byteIndex]); // (ushort)(bytes[byteIndex++] | bytes[byteIndex++] << 8);
            byteIndex += 2;
            return value;
        }

        /// <summary> 读取Int16(2字节 有符号整数 小端序) | Read Int16(2 bytes signed integer little-endian) </summary>
        public short ReadInt16() {
            return (short)ReadUInt16();
        }

        /// <summary> 读取UInt32(4字节 无符号整数 小端序) | Read UInt32(4 bytes unsigned integer little-endian) </summary>
        public uint ReadUInt32() {
            uint value = Unsafe.As<byte, uint>(ref bytes[byteIndex]); // (uint)(bytes[byteIndex++] | bytes[byteIndex++] << 8 | bytes[byteIndex++] << 16 | bytes[byteIndex++] << 24);
            byteIndex += 4;
            return value;
        }

        /// <summary> 读取UInt32(4字节 有符号整数 小端序) | Read Int32(4 bytes signed integer little-endian) </summary>
        public int ReadInt32() {
            return (int)ReadUInt32();
        }

        /// <summary> 读取UInt64(8字节 无符号整数 小端序) | Read UInt64(8 bytes unsigned integer little-endian) </summary>
        public ulong ReadUInt64() {
            ulong value = Unsafe.As<byte, ulong>(ref bytes[byteIndex]); // int low = bytes[byteIndex++] | bytes[byteIndex++] << 8 | bytes[byteIndex++] << 16 | bytes[byteIndex++] << 24;
            byteIndex += 8;                                             // int high = bytes[byteIndex++] | bytes[byteIndex++] << 8 | bytes[byteIndex++] << 16 | bytes[byteIndex++] << 24;
            return value;                                               // return (uint)low | (ulong)high << 32;
        }

        /// <summary> 读取Int64(8字节 有符号整数 小端序) | Read Int64(8 bytes signed integer little-endian) </summary>
        public long ReadInt64() {
            return (long)ReadUInt64();
        }
        #endregion

        #region 浮点数 | Float
        /// <summary> 读取半精度浮点数(2字节 IEEE754 float16) | Read Float16(2 bytes IEEE754 float16) </summary>
        public Half ReadFloat16() {
            ushort bits = ReadUInt16();                 // ushort bits = ReadUInt16(); Half f = (Half)0;
            return Unsafe.As<ushort, Half>(ref bits);   // unsafe { f = *(Half*)&bits; } return f;
        }

        /*
        /// <summary> 读取半精度浮点数(2字节 IEEE754 float16) | Read Float16(2 bytes IEEE754 float16) </summary>
        public float ReadFloat16() {
            uint bits = bytes[byteIndex++] | (uint)bytes[byteIndex++] << 8;
            uint sign = bits >> 15;
            uint exponent = (bits >> 10) & 0x1F;
            uint mantissa = bits & 0x3FF;
            if (exponent == 0x1F) {
                if (mantissa == 0) {
                    return sign == 0 ? float.PositiveInfinity : float.NegativeInfinity;
                } else {
                    return float.NaN;
                }
            } else if (exponent == 0 && mantissa == 0) {
                return sign == 0 ? 0f : -0f;
            } else {
                // 正常值 Half -> Float
                // [Sign(1bit) Exponent(5bits) Mantissa(10bits) Bias(15)] -> [Sign(1bit) Exponent(8bits) Mantissa(23bits) Bias(127)]
                // [S EEEEE MM MMMMMMMM] -> [S EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMM]
                exponent = exponent - 15 + 127;
                bits = sign << 31 | exponent << 23 | mantissa << 13;
                float f = 0f;
                unsafe { f = *(float*)&bits; }
                f = RoundSignificantDigits(f, 3);
                return f;
            }
        }

        /// <summary> 保留N位有效数字 </summary>
        private static float RoundSignificantDigits(float f, int n) {
            if (f == 0f || f == -0f || f == float.PositiveInfinity || f == float.NegativeInfinity || float.IsNaN(f)) return f;
            double num = f;
            int power = n - (int)Math.Ceiling(Math.Log10(num < 0.0 ? -num : num));
            double magnitude = Math.Pow(10, power);
            long shift = (long)Math.Round(num * magnitude);
            return (float)(shift / magnitude);
        }
        */

        /*
        public float ReadFloat24() {
            // Float24 (Custom 24-bit) to Float32(IEEE 754 32-bit)
            // [Sign(1bit) Exponent(7bits) Mantissa(16bits) Bias(63)] -> [Sign(1bit) Exponent(8bits) Mantissa(23bits) Bias(127)]
            // [S EEEEEEE MMMMMMMM MMMMMMMM] -> [S EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMM]
        }
        */

        /// <summary> 读取单精度浮点数(4字节 IEEE754 float32) | Read Float32(4 bytes IEEE754 float32) </summary>
        public float ReadFloat32() {
            uint bits = ReadUInt32();                   // uint bits = ReadUInt32(); float f = 0f;
            return Unsafe.As<uint, float>(ref bits);    // return unsafe { f = *(float*)&bits; } return f;
        }

        /// <summary> 读取双精度浮点数(8字节 IEEE754 float64) | Read double(8 bytes IEEE754 float64) </summary>
        public double ReadFloat64() {
            ulong bits = ReadUInt64();                  // ulong bits = ReadUInt64(); double d = 0d;
            return Unsafe.As<ulong, double>(ref bits);  // return unsafe { d = *(double*)&bits; } return d;
        }
        #endregion

        #region 变长整数 | Variable-length Integer
        protected uint ReadVUInt32(int byteCount) {
            uint value = 0;
            for (int i = 0; i < byteCount; i++) {
                value = value | ((uint)bytes[byteIndex++] << (i * 8));
            }
            return value;
        }

        protected ulong ReadVUInt64(int byteCount) {
            ulong value = 0;
            for (int i = 0; i < byteCount; i++) {
                value = value | ((ulong)bytes[byteIndex++] << (i * 8));
            }
            return value;
        }

        public ushort ReadVUInt16() {
            return ReadBit1() ? ReadUInt16() : ReadUInt8();
        }

        public short ReadVInt16() {
            int byteCount = ReadBits(1) + 1;
            uint bits = ReadVUInt32(byteCount);
            uint sign = bits & VInt32SignMask[byteCount];
            uint value = bits & VInt32ValueMask[byteCount];
            return (short)(sign == 0 ? value : ~value);
        }

        public uint ReadVUInt32() {
            return ReadVUInt32(ReadBits(2) + 1);
        }

        public int ReadVInt32() {
            int byteCount = ReadBits(2) + 1;
            uint bits = ReadVUInt32(byteCount);
            uint sign = bits & VInt32SignMask[byteCount];
            uint value = bits & VInt32ValueMask[byteCount];
            return (int)(sign == 0 ? value : ~value);
        }

        public ulong ReadVUInt64() {
            return ReadVUInt64(ReadBits(3) + 1);
        }

        public long ReadVInt64() {
            int byteCount = ReadBits(3) + 1;
            ulong bits = ReadVUInt64(byteCount);
            ulong sign = bits & VInt64SignMask[byteCount];
            ulong value = bits & VInt64ValueMask[byteCount];
            return (long)(sign == 0 ? value : ~value);
        }
        #endregion

        #region API
        /// <summary> 跳过指定字节数(不包括已经读取的位) | Skip byte count(exclude bit) </summary>
        public void Skip(int byteCount) {
            byteIndex += byteCount;
        }

        /// <summary> 当前读取的数据 | Data currently read </summary>
        public byte[] Bytes {
            get { return bytes; }
            set {
                Position = 0;
                bytes = value;
            }
        }

        /// <summary> 当前读取的字节位置(设置时 位的位置会被重置) | Byte position(when set value bit location will be reset) </summary>
        public int Position {
            get { return byteIndex; }
            set {
                if (value < 0) throw new ArgumentNullException("Position", "Position can't be negative!");
                byteIndex = value;
                bitByteIndex = -1;
                bitIndex = 8;
            }
        }

        /// <summary> 释放并销毁所有数据 | Release and destroy all datas </summary>
        public void Dispose() {
            Position = 0;
            bytes = null;
        }
        #endregion

    }

}
